﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Data;
using System.Collections;
using System.ComponentModel;
using System.Windows.Threading;
using System.Threading;

namespace SwiftMVVM.Behaviors
{
    /// <summary>
    /// DataGridBehavior defines a set of reusable behaviors normally coded against a DataGrid.
    /// Such as AutoSelecting and scrolling the ActiveRow of a view into view
    /// </summary>
    public sealed class DataGridBehavior
    {
        /// <summary>
        /// Controls the auto click style of the grid when the user sets focus to it
        /// </summary>
        public enum ClickType
        {
            SingleClick,
            DoubleClick
        }

        /// <summary>
        /// EditClickAction Dependency property declaration
        /// </summary>
        public static readonly DependencyProperty EditClickActionProperty =
           DependencyProperty.RegisterAttached(
           "EditClickAction",
           typeof(ClickType),
           typeof(DataGridBehavior),
           new FrameworkPropertyMetadata(ClickType.DoubleClick, (d, e) =>
           {
               var dataGrid = d as DataGrid;
               if (dataGrid != null)
               {
                   if (e.NewValue != null &&
                       ((ClickType)e.NewValue) == ClickType.SingleClick)
                   {
                       dataGrid.Loaded += new RoutedEventHandler(dataGrid_LoadedEditClickAction);
                   }
               }

           })
           );

       
        /// <summary>
        /// EditClickAction dependency property getter
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ClickType GetEditClickAction(DependencyObject obj)
        {
            return (ClickType)obj.GetValue(EditClickActionProperty);
        }

        /// <summary>
        /// EditClickAction dependency property setter
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        public static void SetEditClickAction(DependencyObject obj, ClickType value)
        {
            obj.SetValue(EditClickActionProperty, value);
        }

    

   

      


        static void dataGrid_LoadedEditClickAction(object sender, RoutedEventArgs e)
        {
            var dataGrid = (DataGrid)sender;
            dataGrid.Loaded -= new RoutedEventHandler(dataGrid_LoadedEditClickAction);
            Style style = null;
            if (dataGrid.CellStyle == null)
            {
                style = new Style(typeof(DataGridCell));
            }
            else
            {
                style = new Style(typeof(DataGridCell), dataGrid.CellStyle);
            }
            dataGrid.Resources.Remove(typeof(DataGridCell));

            EventSetter eventSetter = new EventSetter(DataGrid.PreviewMouseLeftButtonDownEvent,
                new MouseButtonEventHandler(DataGridCell_PreviewMouseLeftButtonDown));

            style.Setters.Add(eventSetter);
            dataGrid.Resources.Add(typeof(DataGridCell), style);
        }

        private static void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var cell = sender as DataGridCell;
            if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
            {
                if (!cell.IsFocused)
                {
                    cell.Focus();
                }

                var dataGrid = FindVisualParent<DataGrid>(cell);
                if (dataGrid != null)
                {
                    if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
                    {
                        if (!cell.IsSelected)
                            cell.IsSelected = true;
                    }
                    else
                    {
                        var row = FindVisualParent<DataGridRow>(cell);
                        if (row != null && !row.IsSelected)
                        {
                            row.IsSelected = true;
                        }
                    }
                }
            }
        }


        static T FindVisualParent<T>(UIElement element) where T : UIElement
        {
            var parent = element;
            while (parent != null)
            {
                T correctlyTyped = parent as T;
                if (correctlyTyped != null)
                {
                    return correctlyTyped;
                }

                parent = VisualTreeHelper.GetParent(parent) as UIElement;
            }
            return null;
        }

        /// <summary>
        /// Using the AutoScrollCurrentRow implementation from ISolvable
        /// My method had a few issues when the view the grid was bound to changed.
        /// This method is much better
        /// http://isolvable.blogspot.com/2010/03/wpf-datagrid-scrollintoview.html
        /// </summary>
        /// <param name="dataGrid"></param>
        /// <returns></returns>
        #region AutoScrollCurrentRowIntoView

        public static bool GetAutoScrollCurrentRowIntoView(DataGrid dataGrid)
        {
            return (bool)dataGrid.GetValue(AutoScrollCurrentRowIntoViewProperty);
        }

        public static void SetAutoScrollCurrentRowIntoView(DataGrid dataGrid, bool value)
        {
            dataGrid.SetValue(AutoScrollCurrentRowIntoViewProperty, value);
        }

        public static readonly DependencyProperty AutoScrollCurrentRowIntoViewProperty =
            DependencyProperty.RegisterAttached("AutoScrollCurrentRowIntoView", typeof(bool),
            typeof(DataGridBehavior),
            new UIPropertyMetadata(false, OnAutoScrollIntoViewWhenSelectionChanged));

        static void OnAutoScrollIntoViewWhenSelectionChanged(DependencyObject depObj,
            DependencyPropertyChangedEventArgs e)
        {
            DataGrid dataGrid = depObj as DataGrid;
            if (dataGrid == null)
                return;

            if (!(e.NewValue is bool))
                return;

            if ((bool)e.NewValue)
                dataGrid.SelectionChanged += OnDataGridSelectionChanged;
            else
                dataGrid.SelectionChanged -= OnDataGridSelectionChanged;
        }

        static void OnDataGridSelectionChanged(object sender, RoutedEventArgs e)
        {
            // Only react to the SelectionChanged event raised by the DataGrid   
            // Ignore all ancestors.     
            if (!Object.ReferenceEquals(sender, e.OriginalSource))
                return;

            DataGrid dataGrid = e.OriginalSource as DataGrid;
            if (dataGrid != null && dataGrid.SelectedItem != null)
            {
                // this is a workaround to fix the layout issue.      
                // otherwise ScrollIntoView should work directly.       
                dataGrid.Dispatcher.BeginInvoke(
                    DispatcherPriority.Loaded,
                    new DispatcherOperationCallback(ScrollItemIntoView), dataGrid);
            }
        }

        static object ScrollItemIntoView(object sender)
        {
            DataGrid dataGrid = sender as DataGrid;
            if (dataGrid != null && dataGrid.SelectedItem != null)
            {
                dataGrid.ScrollIntoView(dataGrid.SelectedItem);
            }
            return null;
        }
        #endregion
    }
}
